/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.aspectj.annotation;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 *
 *	@EnableAspectJAutoProxy  开启aop功能的注解
 *		@Import(AspectJAutoProxyRegistrar.class)	往容器中导入了一个组件 AspectJAutoProxyRegistrar
 *			 AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar 往容器中注册了一个bd信息，	AnnotationAwareAspectJAutoProxyCreator
 *
 * <p>分析这个AnnotationAwareAspectJAutoProxyCreator<p/>
 * 首先看继承关系：整个继承关系如下：
 * 	AnnotationAwareAspectJAutoProxyCreator  ---initBeanFactory
 *		AspectJAwareAdvisorAutoProxyCreator
 *				AbstractAdvisorAutoProxyCreator  ---setBeanFactory   ---initBeanFactory
 *					AbstractAutoProxyCreator  ---setBeanFactory
 *						SmartInstantiationAwareBeanPostProcessor   BeanFactoryAware
 *							InstantiationAwareBeanPostProcessor
 *								BeanPostProcessor
 *
 *
 * <p>AnnotationAwareAspectJAutoProxyCreator的加载时机</p>
 * 在spring 的 ioc 容器创建过程中的 refresh方法中，有一个步骤叫做：
 * invokeBeanFactoryPostProcessors
 * 		invokeBeanDefinitionRegistryPostProcessors
 * 			postProcessBeanDefinitionRegistry
 * 				processConfigBeanDefinitions
 * 					loadBeanDefinitions
 * 						loadBeanDefinitionsForConfigurationClass
 * 							loadBeanDefinitionsFromRegistrars
 * 								ImportBeanDefinitionRegistrar.registerBeanDefinitions(internalAutoProxyCreator)
 *
 * 	registerBeanPostProcessors()
 * 		initializeBean()
 * 			invokeAwareMethods()
 * 				setBeanFactory()
 * 					initBeanFactory()
 * <p>AnnotationAwareAspectJAutoProxyCreator的执行时机</p>
 * finishBeanFactoryInitialization()
 *		beanFactory.preInstantiateSingletons()
 *			getBean(beanName)
 *				doGetBean(name, null, null, false)
 *					createBean(beanName, mbd, args)
 *						resolveBeforeInstantiation(beanName, mbdToUse)
 *							applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)
 *								InstantiationAwareBeanPostProcessor	的before方法 （AnnotationAwareAspectJAutoProxyCreator）会在任何bean创建之前尝试去返回一个代理对象
 *							applyBeanPostProcessorsAfterInitialization(bean, beanName)
 *						doCreateBean(beanName, mbdToUse, args)
 *							createBeanInstance(beanName, mbd, args)
 *								instantiateBean(beanName, mbd)
 *									getInstantiationStrategy().instantiate(mbd, beanName, this)
 *				    populateBean(beanName, mbd, instanceWrapper)
 *				    initializeBean(beanName, exposedObject, mbd)
 * <p>创建AOP代理对象</p>
 * initializeBean(beanName, exposedObject, mbd)
 * 		applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
 * 		invokeInitMethods(beanName, wrappedBean, mbd)
 * 		applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
 * 			processor.postProcessAfterInitialization(result, beanName)
 * 				wrapIfNecessary(bean, beanName, cacheKey)
 * 					createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
 *						proxyFactory.getProxy(classLoader)
 *							createAopProxy()
 *								return new ObjenesisCglibAopProxy(config) || new JdkDynamicAopProxy(config)
 * <p>获取拦截器链</p>
 *	目标方法执行
 *		CglibAopProxy.intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)  拦截目标方法
 *			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 获取目标方法将要执行的拦截器链
 *				this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)
 *					interceptorList 保存所有的拦截器  4个通知方法+ 1个默认增强器
 *					遍历所有的增强器将其转换为	interceptor   registry.getInterceptors(advisor)
 *					将增强器转换为List<MethodInterceptor>
 *					 如果是   MethodInterceptor 直接加入到集合
 *					 如果不是，使用AdvisorAdapter将增强器转换为Interceptor
 *			如果没有拦截器链，直接执行目标方法
 *			如果有拦截器链，把需要执行的目标对象，目标方法，拦截器链的所有信息传入创建一个cglib对象，并调用proceed()。
 *			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
 * <p>链式调用通知方法</p>
 * proceed()
 * 		super.proceed()
 * 			((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
 * 				mi.proceed()
 *		proceed()
 *			(AspectJMethodBeforeAdvice, AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice,AspectJAfterAdvice)
 *			this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis())
 *			mi.proceed()
 *
 *
 *		   invokeAdviceMethod(getJoinPointMatch(), null, null)
 * 		如果没有拦截器执行目标方法，或者拦截器的索引和拦截器数组-1 大小一样（指定到了最后一个拦截器）执行目标方法。
 * 		链式获取每一个拦截器，拦截器执行invoke方法，每一个拦截器等待下一个拦截器执行完成返回以后在执行。
 * 		拦截器链的机制，保证通知方法与目标方法的执行顺序。
 * <p>AOP源码总结</p>
 * 			1）、  @EnableAspectJAutoProxy 开启AOP功能
 *   		2）、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
 *   		3）、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器；
 *   		4）、容器的创建流程：
 *   			1）、registerBeanPostProcessors（）注册后置处理器；创建AnnotationAwareAspectJAutoProxyCreator对象
 *   			2）、finishBeanFactoryInitialization（）初始化剩下的单实例bean
 *   				1）、创建业务逻辑组件和切面组件
 *   				2）、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
 *   				3）、组件创建完之后，判断组件是否需要增强
 *   					是：切面的通知方法，包装成增强器（Advisor）;给业务逻辑组件创建一个代理对象（cglib）；
 *   		5）、执行目标方法：
 *   			1）、代理对象执行目标方法
 *   			2）、CglibAopProxy.intercept()；
 *   				1）、得到目标方法的拦截器链（增强器包装成拦截器MethodInterceptor）
 *   				2）、利用拦截器的链式机制，依次进入每一个拦截器进行执行；
 *   				3）、效果：
 *   					正常执行：前置通知-》目标方法-》后置通知-》返回通知
 *   					出现异常：前置通知-》目标方法-》后置通知-》异常通知
 *
 *
 *
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 2.0
 * @see org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory
 */
@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {


	/**
	 * ctrl + H 查看类的继承关系：
	 *
	 */
	@Nullable
	private List<Pattern> includePatterns;

	@Nullable
	private AspectJAdvisorFactory aspectJAdvisorFactory;

	@Nullable
	private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;


	/**
	 * Set a list of regex patterns, matching eligible @AspectJ bean names.
	 * <p>Default is to consider all @AspectJ beans as eligible.
	 */
	public void setIncludePatterns(List<String> patterns) {
		this.includePatterns = new ArrayList<>(patterns.size());
		for (String patternText : patterns) {
			this.includePatterns.add(Pattern.compile(patternText));
		}
	}

	public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
		Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
	}

	@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		if (this.aspectJAdvisorFactory == null) {
			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
		}
		this.aspectJAdvisorsBuilder =
				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
	}


	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// 调用父类的方法 查询出来 bf 里面所有的增强器
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			//这里通过builder进行构建了一个 增强器集合
			//builder是怎么来的？ initFactory方法里面显式new 了一个 构建器的适配器
			//提取切面类上的@Aspectj注解信息
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

	@Override
	protected boolean isInfrastructureClass(Class<?> beanClass) {
		// Previously we setProxyTargetClass(true) in the constructor, but that has too
		// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
		// aspects. I'm not entirely happy with that as there is no good reason not
		// to advise aspects, except that it causes advice invocation to go through a
		// proxy, and if the aspect implements e.g the Ordered interface it will be
		// proxied by that interface and fail at runtime as the advice method is not
		// defined on the interface. We could potentially relax the restriction about
		// not advising aspects in the future.
		return (super.isInfrastructureClass(beanClass) ||
				(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
	}

	/**
	 * Check whether the given aspect bean is eligible for auto-proxying.
	 * <p>If no &lt;aop:include&gt; elements were used then "includePatterns" will be
	 * {@code null} and all beans are included. If "includePatterns" is non-null,
	 * then one of the patterns must match.
	 */
	protected boolean isEligibleAspectBean(String beanName) {
		if (this.includePatterns == null) {
			return true;
		}
		else {
			for (Pattern pattern : this.includePatterns) {
				if (pattern.matcher(beanName).matches()) {
					return true;
				}
			}
			return false;
		}
	}


	/**
	 * Subclass of BeanFactoryAspectJAdvisorsBuilderAdapter that delegates to
	 * surrounding AnnotationAwareAspectJAutoProxyCreator facilities.
	 */
	private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {

		public BeanFactoryAspectJAdvisorsBuilderAdapter(
				ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {

			super(beanFactory, advisorFactory);
		}

		@Override
		protected boolean isEligibleBean(String beanName) {
			return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
		}
	}

}
